home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / MoreFiles 1.3.1 / MoreDesktopMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-30  |  29.9 KB  |  1,145 lines  |  [TEXT/MMCC]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    A collection of useful high-level Desktop Manager routines.
  5. **    If the Desktop Manager isn't available, use the Desktop file
  6. **    for 'read' operations.
  7. **
  8. **    We do more because we can...
  9. **
  10. **    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support
  11. **
  12. **    File:    MoreDesktopMgr.c
  13. **
  14. **    Copyright © 1992-1995 Apple Computer, Inc.
  15. **    All rights reserved.
  16. **
  17. **    You may incorporate this sample code into your applications without
  18. **    restriction, though the sample code has been provided "AS IS" and the
  19. **    responsibility for its operation is 100% yours.  However, what you are
  20. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  21. **    after having made changes. If you're going to re-distribute the source,
  22. **    we require that you make it clear in the source that the code was
  23. **    descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. #include <Types.h>
  27. #include <Errors.h>
  28. #include <Memory.h>
  29. #include <Files.h>
  30. #include <Resources.h>
  31. #include <Icons.h>
  32. #include "MoreFiles.h"
  33. #include "MoreFilesExtras.h"
  34. #include "Search.h"
  35. #include "MoreDesktopMgr.h"
  36.  
  37. /*****************************************************************************/
  38.  
  39. /*    Desktop file notes:
  40. **
  41. **    •    The Desktop file is owned by the Finder and is normally open by the
  42. **        Finder. That means that we only have read-only access to the Desktop
  43. **        file.
  44. **    •    Since the Resource Manager doesn't support shared access to resource
  45. **        files and we're using read-only access, we don't ever leave the
  46. **        Desktop file open.  We open a path to it, get the data we want out
  47. **        of it, and then close the open path. This is the only safe way to
  48. **        open a resource file with read-only access since some other program
  49. **        could have it open with write access.
  50. **    •    The bundle related resources in the Desktop file are normally
  51. **        purgable, so when we're looking through them, we don't bother to
  52. **        release resources we're done looking at - closing the resource file
  53. **        (which we always do) will release them.
  54. **    •    Since we can't assume the Desktop file is named "Desktop"
  55. **        (it probably is everywhere but France), we get the Desktop
  56. **        file's name by searching the volume's root directory for a file
  57. **        with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
  58. **        this scheme is that someone could create another file with that type
  59. **        and creator in the root directory and we'd find the wrong file.
  60. **        The chances of this are very slim.
  61. */
  62.  
  63. /*****************************************************************************/
  64.  
  65. /* local defines */
  66.  
  67. enum
  68. {
  69.     kBNDLResType    = 'BNDL',
  70.     kFREFResType    = 'FREF',
  71.     kIconFamResType    = 'ICN#',
  72.     kFCMTResType    = 'FCMT',
  73.     kAPPLResType    = 'APPL'
  74. };
  75.  
  76. /*****************************************************************************/
  77.  
  78. /* local data structures */
  79.  
  80. struct IDRec
  81. {
  82.     short        localID;
  83.     short        rsrcID;
  84. };
  85. typedef struct IDRec IDRec;
  86. typedef    IDRec *IDRecPtr;
  87.  
  88. struct BundleType
  89. {
  90.     OSType        type;            /* 'ICN#' or 'FREF' */
  91.     short        count;            /* number of IDRecs - 1 */
  92.     IDRec        idArray[1];
  93. };
  94. typedef struct BundleType BundleType;
  95. typedef BundleType *BundleTypePtr;
  96.  
  97. struct BNDLRec
  98. {
  99.     OSType        signature;        /* creator type signature */
  100.     short        versionID;        /* version - should always be 0 */
  101.     short        numTypes;        /* number of elements in typeArray - 1 */
  102.     BundleType    typeArray[1];
  103. };
  104. typedef struct BNDLRec BNDLRec;
  105. typedef BNDLRec **BNDLRecHandle;
  106.  
  107. struct FREFRec
  108. {
  109.     OSType        fileType;        /* file type */
  110.     short        iconID;            /* icon local ID */
  111.     Str255        fileName;        /* file name */
  112. };
  113. typedef struct FREFRec FREFRec;
  114. typedef FREFRec **FREFRecHandle;
  115.  
  116. struct APPLRec
  117. {
  118.     OSType        creator;        /* creator type signature */
  119.     long        parID;            /* parent directory ID */
  120.     Str255        applName;        /* application name */
  121. };
  122. typedef struct APPLRec APPLRec;
  123. typedef APPLRec *APPLRecPtr;
  124.  
  125. /*****************************************************************************/
  126.  
  127. /* static prototypes */
  128.  
  129. static    OSErr    GetDesktopFileName(short vRefNum,
  130.                                    Str255 desktopName);
  131.  
  132. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  133.                                        short vRefNum,
  134.                                        OSType creator,
  135.                                        short *applVRefNum,
  136.                                        long *applParID,
  137.                                        Str255 applName);
  138.  
  139. static    OSErr    FindBundleGivenCreator(OSType creator,
  140.                                        BNDLRecHandle *returnBndl);
  141.                                        
  142. static    OSErr    FindTypeInBundle(OSType typeToFind,
  143.                                  BNDLRecHandle theBndl,
  144.                                  BundleTypePtr *returnBundleType);
  145.                                          
  146. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  147.                                    OSType fileType,
  148.                                    short *iconLocalID);
  149.  
  150. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  151.                                          short iconLocalID,
  152.                                          short *iconRsrcID);
  153.  
  154. static    OSType    DTIconToResIcon(short iconType);
  155.  
  156. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  157.                                        short vRefNum,
  158.                                        short iconType,
  159.                                        OSType fileCreator,
  160.                                        OSType fileType,
  161.                                        Handle *iconHandle);
  162.  
  163. static    OSErr    GetCommentID(short vRefNum,
  164.                              long dirID,
  165.                              StringPtr name,
  166.                              short *commentID);
  167.  
  168. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  169.                                           long dirID,
  170.                                           StringPtr name,
  171.                                           Str255 comment);
  172.  
  173. /*****************************************************************************/
  174.  
  175. /*
  176. **    GetDesktopFileName
  177. **
  178. **    Get the name of the Desktop file.
  179. */
  180. static    OSErr    GetDesktopFileName(short vRefNum,
  181.                                    Str255 desktopName)
  182. {
  183.     OSErr            error;
  184.     HParamBlockRec    pb;
  185.     short            index;
  186.     Boolean            found = false;
  187.     
  188.     pb.fileParam.ioNamePtr = desktopName;
  189.     pb.fileParam.ioVRefNum = vRefNum;
  190.     pb.fileParam.ioFVersNum = 0;
  191.     index = 1;
  192.     do
  193.     {
  194.         pb.fileParam.ioDirID = fsRtDirID;
  195.         pb.fileParam.ioFDirIndex = index;
  196.         error = PBHGetFInfoSync(&pb);
  197.         if ( error == noErr )
  198.         {
  199.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  200.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  201.             {
  202.                 found = true;
  203.             }
  204.         }
  205.         ++index;
  206.     } while ( (error == noErr) && !found );
  207.     
  208.     return ( error );
  209. }
  210.  
  211. /*****************************************************************************/
  212.  
  213. pascal    OSErr    DTOpen(StringPtr volName,
  214.                        short vRefNum,
  215.                        short *dtRefNum,
  216.                        Boolean *newDTDatabase)
  217. {
  218.     OSErr error;
  219.     GetVolParmsInfoBuffer volParmsInfo;
  220.     long infoSize;
  221.     DTPBRec pb;
  222.     
  223.     /* Check for volume Desktop Manager support before calling */
  224.     infoSize = sizeof(GetVolParmsInfoBuffer);
  225.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  226.     if ( error == noErr )
  227.     {
  228.         if ( hasDesktopMgr(volParmsInfo) )
  229.         {
  230.             pb.ioNamePtr = volName;
  231.             pb.ioVRefNum = vRefNum;
  232.             error = PBDTOpenInform(&pb);
  233.             /* PBDTOpenInform informs us if the desktop was just created */
  234.             /* by leaving the low bit of ioTagInfo clear (0) */
  235.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  236.             if ( error == paramErr )
  237.             {
  238.                 error = PBDTGetPath(&pb);
  239.                 /* PBDTGetPath doesn't tell us if the database is new */
  240.                 /* so assume it is not new */
  241.                 *newDTDatabase = false;
  242.             }
  243.             *dtRefNum = pb.ioDTRefNum;
  244.         }
  245.         else
  246.             error = paramErr;
  247.     }
  248.     return ( error );
  249. }
  250.  
  251. /*****************************************************************************/
  252.  
  253. /*
  254. **    GetAPPLFromDesktopFile
  255. **
  256. **    Get a application's location from the
  257. **    Desktop file's 'APPL' resources.
  258. */
  259. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  260.                                        short vRefNum,
  261.                                        OSType creator,
  262.                                        short *applVRefNum,
  263.                                        long *applParID,
  264.                                        Str255 applName)
  265. {
  266.     OSErr error;
  267.     short realVRefNum;
  268.     Str255 desktopName;
  269.     short savedResFile;
  270.     short dfRefNum;
  271.     Handle applResHandle;
  272.     Boolean foundCreator;
  273.     Ptr applPtr;
  274.     long applSize;
  275.     
  276.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  277.     if ( error == noErr )
  278.     {
  279.         error = GetDesktopFileName(realVRefNum, desktopName);
  280.         if ( error == noErr )
  281.         {
  282.             savedResFile = CurResFile();
  283.             /*
  284.             **    Open the 'Desktop' file in the root directory. (because
  285.             **    opening the resource file could preload unwanted resources,
  286.             **    bracket the call with SetResLoad(s))
  287.             */
  288.             SetResLoad(false);
  289.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  290.             SetResLoad(true);
  291.             
  292.             if ( dfRefNum != -1)
  293.             {
  294.                 /* Get 'APPL' resource ID 0 */
  295.                 applResHandle = Get1Resource(kAPPLResType, 0);
  296.                 if ( applResHandle != NULL )
  297.                 {
  298.                     applSize = GetHandleSize((Handle)applResHandle);
  299.                     if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
  300.                     {
  301.                         foundCreator = false;
  302.                         applPtr = *applResHandle;
  303.                         
  304.                         /* APPL's don't have a count so I have to use the size as the bounds */
  305.                         while ( (foundCreator == false) &&
  306.                                 (applPtr < (*applResHandle + applSize)) )
  307.                         {
  308.                             if ( ((APPLRecPtr)applPtr)->creator == creator )
  309.                             {
  310.                                 foundCreator = true;
  311.                             }
  312.                             else
  313.                             {
  314.                                 /* fun with pointer math... */
  315.                                 applPtr += sizeof(OSType) +
  316.                                            sizeof(long) +
  317.                                            ((APPLRecPtr)applPtr)->applName[0] + 1;
  318.                                 /* application mappings are word aligned within the resource */
  319.                                 if ( ((unsigned long)applPtr % 2) != 0 )
  320.                                     applPtr += 1;
  321.                             }
  322.                         }
  323.                         if ( foundCreator == true )
  324.                         {
  325.                             *applVRefNum = realVRefNum;
  326.                             *applParID = ((APPLRecPtr)applPtr)->parID;
  327.                             BlockMoveData(((APPLRecPtr)applPtr)->applName,
  328.                                           applName,
  329.                                           ((APPLRecPtr)applPtr)->applName[0] + 1);
  330.                             error = noErr;
  331.                         }
  332.                     }
  333.                     else
  334.                         error = afpItemNotFound;    /* no APPL mapping available */
  335.                 }
  336.                 else
  337.                     error = afpItemNotFound;    /* no APPL mapping available */
  338.                 
  339.                 /* restore the resource chain and close the Desktop file */
  340.                 UseResFile(savedResFile);
  341.                 CloseResFile(dfRefNum);
  342.             }
  343.             else
  344.                 error = afpItemNotFound;
  345.         }
  346.     }
  347.     return ( error );
  348. }
  349.  
  350. /*****************************************************************************/
  351.  
  352. pascal    OSErr    DTGetAPPL(StringPtr volName,
  353.                           short vRefNum,
  354.                           OSType creator,
  355.                           short *applVRefNum,
  356.                           long *applParID,
  357.                           Str255 applName)
  358. {
  359.     OSErr error;
  360.     UniversalFMPB pb;
  361.     short dtRefNum;
  362.     Boolean newDTDatabase;
  363.     short realVRefNum;
  364.     short index;
  365.     Boolean applFound;
  366.     FSSpec spec;
  367.     long actMatchCount;
  368.     
  369.     /* get the real vRefNum */
  370.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  371.     if ( error == noErr )
  372.     {
  373.         error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  374.         if ( error == noErr )
  375.         {
  376.             if ( !newDTDatabase )
  377.             {
  378.                 index = 0;
  379.                 applFound = false;
  380.                 do
  381.                 {
  382.                     pb.dtPB.ioNamePtr = applName;
  383.                     pb.dtPB.ioDTRefNum = dtRefNum;
  384.                     pb.dtPB.ioIndex = index;
  385.                     pb.dtPB.ioFileCreator = creator;
  386.                     error = PBDTGetAPPLSync(&pb.dtPB);
  387.                     if ( error == noErr )
  388.                     {
  389.                         /* got a match - see if it is valid */
  390.                         
  391.                         *applVRefNum = realVRefNum; /* get the vRefNum now */
  392.                         *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
  393.     
  394.                         /* pb.hPB.fileParam.ioNamePtr is already set */
  395.                         pb.hPB.fileParam.ioVRefNum = realVRefNum;
  396.                         pb.hPB.fileParam.ioFVersNum = 0;
  397.                         pb.hPB.fileParam.ioDirID = *applParID;
  398.                         pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  399.                         if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  400.                         {
  401.                             if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
  402.                                  (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
  403.                             {
  404.                                 applFound = true;
  405.                             }
  406.                         }
  407.                     }
  408.                     ++index;
  409.                 } while ( (error == noErr) && !applFound );
  410.                 if ( error == fnfErr )
  411.                     error = afpItemNotFound;
  412.             }
  413.             else
  414.                 /* Desktop database is empty (new), set error to try CatSearch */
  415.                 error = afpItemNotFound;
  416.         }
  417.         /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
  418.         if ( error == paramErr )
  419.         {
  420.             /* if paramErr, the volume didn't support the Desktop Manager */
  421.             /* try the Desktop file */
  422.             
  423.             error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
  424.                                             applVRefNum, applParID, applName);
  425.             if ( error == noErr )
  426.             {
  427.                 /* got a match - see if it is valid */
  428.                 
  429.                 pb.hPB.fileParam.ioNamePtr = applName;
  430.                 pb.hPB.fileParam.ioVRefNum = *applVRefNum;
  431.                 pb.hPB.fileParam.ioFVersNum = 0;
  432.                 pb.hPB.fileParam.ioDirID = *applParID;
  433.                 pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  434.                 if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  435.                 {
  436.                     if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
  437.                          (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
  438.                     {
  439.                         error = afpItemNotFound;
  440.                     }
  441.                 }
  442.                 else if ( error == fnfErr )
  443.                     error = afpItemNotFound;
  444.             }
  445.         }
  446.         /* acceptable error from DesktopFile code to continue is afpItemNotFound */
  447.         if ( error == afpItemNotFound )
  448.         {
  449.             /* Couldn't be found in the Desktop file either, try searching with CatSearch */
  450.             
  451.             error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
  452.                                             &actMatchCount, true);
  453.             if ( (error == noErr) || (error == eofErr) )
  454.             {
  455.                 if ( actMatchCount > 0 )
  456.                 {
  457.                     *applVRefNum = spec.vRefNum;
  458.                     *applParID = spec.parID;
  459.                     BlockMoveData(spec.name, applName, spec.name[0] + 1);
  460.                 }
  461.                 else
  462.                     error = afpItemNotFound;
  463.             }
  464.         }
  465.     }
  466.     return ( error );
  467. }
  468.  
  469. /*****************************************************************************/
  470.  
  471. pascal    OSErr    FSpDTGetAPPL(StringPtr volName,
  472.                              short vRefNum,
  473.                              OSType creator,
  474.                              FSSpec *spec)
  475. {
  476.     return ( DTGetAPPL(volName, vRefNum, creator,
  477.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  478. }
  479.  
  480. /*****************************************************************************/
  481.  
  482. /*
  483. **    FindBundleGivenCreator
  484. **
  485. **    Search the current resource file for the 'BNDL' resource with the given
  486. **    creator and return a handle to it.
  487. */
  488. static    OSErr    FindBundleGivenCreator(OSType creator,
  489.                                        BNDLRecHandle *returnBndl)
  490. {
  491.     OSErr            error;
  492.     short            numOfBundles;
  493.     short            index;
  494.     BNDLRecHandle    theBndl;
  495.     
  496.     error = afpItemNotFound;    /* default to not found */
  497.     
  498.     /* Search each BNDL resource until we find the one with a matching creator. */
  499.     
  500.     numOfBundles = Count1Resources(kBNDLResType);
  501.     index = 1;
  502.     *returnBndl = NULL;
  503.     
  504.     while ( (index <= numOfBundles) && (*returnBndl == NULL) )
  505.     {
  506.         theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
  507.         
  508.         if ( theBndl != NULL )
  509.         {
  510.             if ( (*theBndl)->signature == creator )
  511.             {
  512.                 /* numTypes and typeArray->count will always be the actual count minus 1, */
  513.                 /* so 0 in both fields is valid. */
  514.                 if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
  515.                 {
  516.                     /* got it */
  517.                     *returnBndl = theBndl;
  518.                     error = noErr;
  519.                 }
  520.             }
  521.         }    
  522.         
  523.         index ++;
  524.     }
  525.     
  526.     return ( error );
  527. }
  528.  
  529. /*****************************************************************************/
  530.  
  531. /*
  532. **    FindTypeInBundle
  533. **
  534. **    Given a Handle to a BNDL return a pointer to the desired type
  535. **    in it. If the type is not found, or if the type's count < 0,
  536. **    return afpItemNotFound.
  537. */
  538. static    OSErr    FindTypeInBundle(OSType typeToFind,
  539.                                  BNDLRecHandle theBndl,
  540.                                  BundleTypePtr *returnBundleType)
  541. {
  542.     OSErr            error;
  543.     short            index;
  544.     Ptr                ptrIterator;    /* use a Ptr so we can do ugly pointer math */
  545.     
  546.     error = afpItemNotFound;    /* default to not found */
  547.     
  548.     ptrIterator = (Ptr)((*theBndl)->typeArray);
  549.     index = 0;
  550.     *returnBundleType = NULL;
  551.  
  552.     while ( (index < ((*theBndl)->numTypes + 1)) &&
  553.             (*returnBundleType == NULL) )
  554.     {
  555.         if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
  556.              (((BundleTypePtr)ptrIterator)->count >= 0) )
  557.         {
  558.                 *returnBundleType = (BundleTypePtr)ptrIterator;
  559.                 error = noErr;
  560.         }
  561.         else
  562.         {
  563.             ptrIterator += ( sizeof(OSType) +
  564.                              sizeof(short) +
  565.                              ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
  566.             ++index;
  567.         }
  568.     }
  569.         
  570.     return ( error );
  571. }
  572.  
  573. /*****************************************************************************/
  574.  
  575. /*
  576. **    GetLocalIDFromFREF
  577. **
  578. **    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
  579. **    looking for a matching fileType. If a matching fileType is found, return
  580. **    its icon local ID. If no match is found, return afpItemNotFound as the
  581. **    function result.
  582. */
  583. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  584.                                    OSType fileType,
  585.                                    short *iconLocalID)
  586. {
  587.     OSErr            error;
  588.     short            index;
  589.     IDRecPtr        idIterator;
  590.     FREFRecHandle    theFref;
  591.     
  592.     error = afpItemNotFound;    /* default to not found */
  593.     
  594.     /* For each localID in this type, get the FREF resource looking for fileType */
  595.     index = 0;
  596.     idIterator = &theBundleType->idArray[0];
  597.     *iconLocalID = 0;
  598.     
  599.     while ( (index <= (theBundleType->count + 1)) && (*iconLocalID == 0) )
  600.     {
  601.         theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
  602.         if ( theFref != NULL )
  603.         {
  604.             if ( (*theFref)->fileType == fileType )
  605.             {
  606.                 *iconLocalID = (*theFref)->iconID;
  607.                 error = noErr;
  608.             }
  609.         }
  610.         
  611.         ++idIterator;
  612.         ++index;
  613.     }
  614.     
  615.     return ( error );
  616. }
  617.  
  618. /*****************************************************************************/
  619.  
  620. /*
  621. **    GetIconRsrcIDFromLocalID
  622. **
  623. **    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
  624. **    the localID that matches iconLocalID. If a matching IDRec is found,
  625. **    return the IDRec's rsrcID field value. If no match is found, return
  626. **    afpItemNotFound as the function result.
  627. */
  628. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  629.                                          short iconLocalID,
  630.                                          short *iconRsrcID)
  631. {
  632.     OSErr        error;
  633.     short        index;
  634.     IDRecPtr    idIterator;
  635.     
  636.     error = afpItemNotFound;    /* default to not found */
  637.     
  638.     /* Find the rsrcID of the icon family type, given the localID */
  639.     index = 0;
  640.     idIterator = &theBundleType->idArray[0];
  641.     *iconRsrcID = 0;
  642.     
  643.     while ( (index <= (theBundleType->count+1)) && (*iconRsrcID == 0) )
  644.     {
  645.         if ( idIterator->localID == iconLocalID )
  646.         {
  647.             *iconRsrcID = idIterator->rsrcID;
  648.             error = noErr;
  649.         }
  650.         
  651.         idIterator ++;
  652.         index ++;
  653.     }
  654.     
  655.     return ( error );
  656. }
  657.  
  658. /*****************************************************************************/
  659.  
  660. /*
  661. **    DTIconToResIcon
  662. **
  663. **    Map a Desktop Manager icon type to the corresponding resource type.
  664. **    Return (OSType)0 if there is no corresponding resource type.
  665. */
  666. static    OSType    DTIconToResIcon(short iconType)
  667. {
  668.     OSType    resType;
  669.     
  670.     switch ( iconType )
  671.     {
  672.         case kLargeIcon:
  673.             resType = large1BitMask;
  674.             break;
  675.         case kLarge4BitIcon:
  676.             resType = large4BitData;
  677.             break;
  678.         case kLarge8BitIcon:
  679.             resType = large8BitData;
  680.             break;
  681.         case kSmallIcon:
  682.             resType = small1BitMask;
  683.             break;
  684.         case kSmall4BitIcon:
  685.             resType = small4BitData;
  686.             break;
  687.         case kSmall8BitIcon:
  688.             resType = small8BitData;
  689.             break;
  690.         default:
  691.             resType = (OSType)0;
  692.             break;
  693.     }
  694.     
  695.     return ( resType );
  696. }
  697.  
  698. /*****************************************************************************/
  699.  
  700. /*
  701. **    GetIconFromDesktopFile
  702. **
  703. **    INPUT a pointer to a non-existent Handle, because we'll allocate one
  704. **
  705. **    search each BNDL resource for the right fileCreator and once we get it
  706. **        find the 'FREF' type in BNDL
  707. **        for each localID in the type, open the FREF resource
  708. **            if the FREF is the desired fileType
  709. **                get its icon localID
  710. **                get the ICN# type in BNDL
  711. **                get the icon resource number from the icon localID
  712. **                get the icon resource type from the desktop mgr's iconType
  713. **                get the icon of that type and number
  714. */
  715. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  716.                                        short vRefNum,
  717.                                        short iconType,
  718.                                        OSType fileCreator,
  719.                                        OSType fileType,
  720.                                        Handle *iconHandle)
  721. {
  722.     OSErr            error;
  723.     short            realVRefNum;
  724.     Str255            desktopName;
  725.     short            savedResFile;
  726.     short            dfRefNum;
  727.     BNDLRecHandle    theBndl = NULL;
  728.     BundleTypePtr    theBundleType;
  729.     short            iconLocalID;
  730.     short            iconRsrcID;
  731.     OSType            iconRsrcType;
  732.     Handle            returnIconHandle;    
  733.     char            bndlState;
  734.     
  735.     *iconHandle = NULL;
  736.     
  737.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  738.     if ( error == noErr )
  739.     {
  740.         error = GetDesktopFileName(realVRefNum, desktopName);
  741.         if ( error == noErr )
  742.         {
  743.             savedResFile = CurResFile();
  744.         
  745.             /*
  746.             **    Open the 'Desktop' file in the root directory. (because
  747.             **    opening the resource file could preload unwanted resources,
  748.             **    bracket the call with SetResLoad(s))
  749.             */
  750.             SetResLoad(false);
  751.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  752.             SetResLoad(true);
  753.         
  754.             if ( dfRefNum != -1 )
  755.             {
  756.                 /*
  757.                 **    Find the BNDL resource with the specified creator.
  758.                 */
  759.                 error = FindBundleGivenCreator(fileCreator, &theBndl);
  760.                 if ( error == noErr )
  761.                 {
  762.                     /* Lock the BNDL resource so it won't be purged when other resources are loaded */
  763.                     bndlState = HGetState((Handle)theBndl);
  764.                     HLock((Handle)theBndl);
  765.                     
  766.                     /* Find the 'FREF' BundleType record in the BNDL resource. */
  767.                     error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
  768.                     if ( error == noErr )
  769.                     {
  770.                         /* Find the local ID in the 'FREF' resource with the specified fileType */
  771.                         error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
  772.                         if ( error == noErr )
  773.                         {
  774.                             /* Find the 'ICN#' BundleType record in the BNDL resource. */
  775.                             error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
  776.                             if ( error == noErr )
  777.                             {
  778.                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */
  779.                                 error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
  780.                                 if ( error == noErr )
  781.                                 {
  782.                                     /* Map Desktop Manager icon type to resource type */
  783.                                     iconRsrcType = DTIconToResIcon(iconType);
  784.                                     
  785.                                     if ( iconRsrcType != (OSType)0 )
  786.                                     {
  787.                                         /* Load the icon */
  788.                                         returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
  789.                                         if ( returnIconHandle != NULL )
  790.                                         {
  791.                                             /* Copy the resource handle, and return the copy */
  792.                                             HandToHand(&returnIconHandle);
  793.                                             if ( MemError() == noErr )
  794.                                                 *iconHandle = returnIconHandle;
  795.                                             else
  796.                                                 error = afpItemNotFound;
  797.                                         }
  798.                                         else
  799.                                             error = afpItemNotFound;
  800.                                     }
  801.                                 }
  802.                             }
  803.                         }
  804.                     }
  805.                     /* Restore the state of the BNDL resource */ 
  806.                     HSetState((Handle)theBndl, bndlState);
  807.                 }
  808.                 /* Restore the resource chain and close the Desktop file */
  809.                 UseResFile(savedResFile);
  810.                 CloseResFile(dfRefNum);
  811.             }
  812.             else
  813.                 error = ResError(); /* could not open Desktop file */
  814.         }
  815.     }
  816.     
  817.     return ( error );
  818. }
  819.  
  820. /*****************************************************************************/
  821.  
  822. pascal    OSErr    DTGetIcon(StringPtr volName,
  823.                           short vRefNum,
  824.                           short iconType,
  825.                           OSType fileCreator,
  826.                           OSType fileType,
  827.                           Handle *iconHandle)
  828. {
  829.     OSErr error;
  830.     DTPBRec pb;
  831.     short dtRefNum;
  832.     Boolean newDTDatabase;
  833.     Size bufferSize;
  834.     
  835.     *iconHandle = NULL;
  836.     error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  837.     if ( error == noErr )
  838.     {
  839.         /* there was a desktop database and it's now open */
  840.         
  841.         if ( !newDTDatabase )    /* don't bother to look in a new (empty) database */
  842.         {
  843.             /* get the buffer size for the requested icon type */
  844.             switch ( iconType )
  845.             {
  846.                 case kLargeIcon:
  847.                     bufferSize = kLargeIconSize;
  848.                     break;
  849.                 case kLarge4BitIcon:
  850.                     bufferSize = kLarge4BitIconSize;
  851.                     break;
  852.                 case kLarge8BitIcon:
  853.                     bufferSize = kLarge8BitIconSize;
  854.                     break;
  855.                 case kSmallIcon:
  856.                     bufferSize = kSmallIconSize;
  857.                     break;
  858.                 case kSmall4BitIcon:
  859.                     bufferSize = kSmall4BitIconSize;
  860.                     break;
  861.                 case kSmall8BitIcon:
  862.                     bufferSize = kSmall8BitIconSize;
  863.                     break;
  864.                 default:
  865.                     iconType = 0;
  866.                     bufferSize = 0;
  867.                     break;
  868.             }
  869.             if ( bufferSize != 0 )
  870.             {
  871.                 *iconHandle = NewHandle(bufferSize);
  872.                 if ( *iconHandle != NULL )
  873.                 {
  874.                     HLock(*iconHandle);
  875.         
  876.                     pb.ioDTRefNum = dtRefNum;
  877.                     pb.ioTagInfo = 0;
  878.                     pb.ioDTBuffer = **iconHandle;
  879.                     pb.ioDTReqCount = bufferSize;
  880.                     pb.ioIconType = iconType;
  881.                     pb.ioFileCreator = fileCreator;
  882.                     pb.ioFileType = fileType;
  883.                     error = PBDTGetIconSync(&pb);
  884.     
  885.                     HUnlock(*iconHandle);
  886.                     
  887.                     if ( error != noErr )
  888.                     {
  889.                         DisposeHandle(*iconHandle);    /* dispose of the allocated memory */
  890.                         *iconHandle = NULL;
  891.                     }
  892.                 }
  893.                 else
  894.                     error = memFullErr;    /* handle could not be allocated */
  895.             }
  896.             else
  897.                 error = paramErr;    /* unknown icon type requested */
  898.         }
  899.         else
  900.             error = afpItemNotFound;    /* the desktop database was empty - nothing to return */
  901.     }
  902.     else
  903.     {
  904.         /* There is no desktop database - try the Desktop file */
  905.         
  906.         error = GetIconFromDesktopFile(volName, vRefNum, iconType,
  907.                                         fileCreator, fileType, iconHandle);
  908.     }
  909.     
  910.     return ( error );
  911. }
  912.  
  913. /*****************************************************************************/
  914.  
  915. pascal    OSErr    DTSetComment(short vRefNum,
  916.                              long dirID,
  917.                              StringPtr name,
  918.                              ConstStr255Param comment)
  919. {
  920.     DTPBRec pb;
  921.     OSErr error;
  922.     short dtRefNum;
  923.     Boolean newDTDatabase;
  924.  
  925.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  926.     if ( error == noErr )
  927.     {
  928.         pb.ioDTRefNum = dtRefNum;
  929.         pb.ioNamePtr = name;
  930.         pb.ioDirID = dirID;
  931.         pb.ioDTBuffer = (Ptr)&comment[1];
  932.         /* Truncate the comment to 200 characters just in case */
  933.         /* some file system doesn't range check */
  934.         if ( comment[0] <= 200 )
  935.             pb.ioDTReqCount = comment[0];
  936.         else
  937.             pb.ioDTReqCount = 200;
  938.         error = PBDTSetCommentSync(&pb);
  939.     }
  940.     return (error);
  941. }
  942.  
  943. /*****************************************************************************/
  944.  
  945. pascal    OSErr    FSpDTSetComment(const FSSpec *spec,
  946.                               ConstStr255Param comment)
  947. {
  948.     return (DTSetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  949. }
  950.  
  951. /*****************************************************************************/
  952.  
  953. /*
  954. **    GetCommentID
  955. **
  956. **    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  957. **    the file or folders fdComment (frComment) field.
  958. */
  959. static    OSErr    GetCommentID(short vRefNum,
  960.                              long dirID,
  961.                              StringPtr name,
  962.                              short *commentID)
  963. {
  964.     CInfoPBRec pb;
  965.     Str31 tempName;
  966.     OSErr error;
  967.  
  968.     /* Protection against File Sharing problem */
  969.     if ( (name == NULL) || (name[0] == 0) )
  970.     {
  971.         tempName[0] = 0;
  972.         pb.hFileInfo.ioNamePtr = tempName;
  973.         pb.hFileInfo.ioFDirIndex = -1;    /* use ioDirID */
  974.     }
  975.     else
  976.     {
  977.         pb.hFileInfo.ioNamePtr = name;
  978.         pb.hFileInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  979.     }
  980.     pb.hFileInfo.ioVRefNum = vRefNum;
  981.     pb.hFileInfo.ioDirID = dirID;
  982.     error = PBGetCatInfoSync(&pb);
  983.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  984.     return ( error );
  985. }
  986.  
  987. /*****************************************************************************/
  988.  
  989. /*
  990. **    GetCommentFromDesktopFile
  991. **
  992. **    Get a file or directory's Finder comment field (if any) from the
  993. **    Desktop file's 'FCMT' resources.
  994. */
  995. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  996.                                           long dirID,
  997.                                           StringPtr name,
  998.                                           Str255 comment)
  999. {
  1000.     OSErr error;
  1001.     short commentID;
  1002.     short realVRefNum;
  1003.     Str255 desktopName;
  1004.     short savedResFile;
  1005.     short dfRefNum;
  1006.     StringHandle commentHandle;
  1007.     
  1008.     /* Get the comment ID number */
  1009.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  1010.     if ( error == noErr )
  1011.     {
  1012.         if ( commentID != 0 )    /* commentID == 0 means there's no comment */
  1013.         {
  1014.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  1015.             if ( error == noErr )
  1016.             {
  1017.                 error = GetDesktopFileName(realVRefNum, desktopName);
  1018.                 if ( error == noErr )
  1019.                 {
  1020.                     savedResFile = CurResFile();
  1021.                     /*
  1022.                     **    Open the 'Desktop' file in the root directory. (because
  1023.                     **    opening the resource file could preload unwanted resources,
  1024.                     **    bracket the call with SetResLoad(s))
  1025.                     */
  1026.                     SetResLoad(false);
  1027.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  1028.                     SetResLoad(true);
  1029.                     
  1030.                     if ( dfRefNum != -1)
  1031.                     {
  1032.                         /* Get the comment resource */
  1033.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
  1034.                         if ( commentHandle != NULL )
  1035.                         {
  1036.                             if ( GetHandleSize((Handle)commentHandle) > 0 )
  1037.                                 BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
  1038.                             else
  1039.                                 error = afpItemNotFound;    /* no comment available */
  1040.                         }
  1041.                         else
  1042.                             error = afpItemNotFound;    /* no comment available */
  1043.                         
  1044.                         /* restore the resource chain and close the Desktop file */
  1045.                         UseResFile(savedResFile);
  1046.                         CloseResFile(dfRefNum);
  1047.                     }
  1048.                     else
  1049.                         error = ResError();
  1050.                 }
  1051.             }
  1052.         }
  1053.         else
  1054.             error = afpItemNotFound;    /* no comment available */
  1055.     }
  1056.     
  1057.     return ( error );
  1058. }
  1059.  
  1060. /*****************************************************************************/
  1061.  
  1062. pascal    OSErr    DTGetComment(short vRefNum,
  1063.                              long dirID,
  1064.                              StringPtr name,
  1065.                              Str255 comment)
  1066. {
  1067.     DTPBRec pb;
  1068.     OSErr error;
  1069.     short dtRefNum;
  1070.     Boolean newDTDatabase;
  1071.  
  1072.     if (comment != NULL)
  1073.     {
  1074.         comment[0] = 0;    /* return nothing by default */
  1075.         
  1076.         /* attempt to open the desktop database */
  1077.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1078.         if ( error == noErr )
  1079.         {
  1080.             /* There was a desktop database and it's now open */
  1081.             
  1082.             if ( !newDTDatabase )
  1083.             {
  1084.                 pb.ioDTRefNum = dtRefNum;
  1085.                 pb.ioNamePtr = name;
  1086.                 pb.ioDirID = dirID;
  1087.                 pb.ioDTBuffer = (Ptr)&comment[1];
  1088.                 error = PBDTGetCommentSync(&pb);
  1089.                 if (error == noErr)
  1090.                     comment[0] = (unsigned char)pb.ioDTActCount;
  1091.             }
  1092.         }
  1093.         else
  1094.         {
  1095.             /* There is no desktop database - try the Desktop file */
  1096.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  1097.         }
  1098.     }
  1099.     else
  1100.         error = paramErr;
  1101.     
  1102.     return (error);
  1103. }
  1104.  
  1105. /*****************************************************************************/
  1106.  
  1107. pascal    OSErr    FSpDTGetComment(const FSSpec *spec,
  1108.                               Str255 comment)
  1109. {
  1110.     return (DTGetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  1111. }
  1112.  
  1113. /*****************************************************************************/
  1114.  
  1115. pascal    OSErr    DTCopyComment(short srcVRefNum,
  1116.                               long srcDirID,
  1117.                               StringPtr srcName,
  1118.                               short dstVRefNum,
  1119.                               long dstDirID,
  1120.                               StringPtr dstName)
  1121. /* The destination volume must support the Desktop Manager for this to work */
  1122. {
  1123.     OSErr error;
  1124.     Str255 comment;
  1125.  
  1126.     error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
  1127.     if ( (error == noErr) && (comment[0] > 0) )
  1128.     {
  1129.         error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
  1130.     }
  1131.     return (error);
  1132. }
  1133.  
  1134. /*****************************************************************************/
  1135.  
  1136. pascal    OSErr    FSpDTCopyComment(const FSSpec *srcSpec,
  1137.                                const FSSpec *dstSpec)
  1138. /* The destination volume must support the Desktop Manager for this to work */
  1139. {
  1140.     return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  1141.                         dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name));
  1142. }
  1143.  
  1144. /*****************************************************************************/
  1145.